package org.convallaria.infrastruct.ce.util;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis缓存工具类
 * 提供Redis特有的缓存操作
 * 
 * @author gjh
 * @since 2024-09-24
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RedisCacheUtils {

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 设置缓存
     * 
     * @param key 键
     * @param value 值
     */
    public void set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            log.error("设置Redis缓存失败: {}", key, e);
        }
    }

    /**
     * 设置缓存并指定过期时间
     * 
     * @param key 键
     * @param value 值
     * @param timeout 过期时间
     * @param unit 时间单位
     */
    public void set(String key, Object value, long timeout, TimeUnit unit) {
        try {
            redisTemplate.opsForValue().set(key, value, timeout, unit);
        } catch (Exception e) {
            log.error("设置Redis缓存失败: {}", key, e);
        }
    }

    /**
     * 设置缓存并指定过期时间
     * 
     * @param key 键
     * @param value 值
     * @param duration 过期时间
     */
    public void set(String key, Object value, Duration duration) {
        set(key, value, duration.toMillis(), TimeUnit.MILLISECONDS);
    }

    /**
     * 获取缓存
     * 
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            log.error("获取Redis缓存失败: {}", key, e);
            return null;
        }
    }

    /**
     * 获取缓存并指定类型
     * 
     * @param key 键
     * @param type 类型
     * @return 值
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key, Class<T> type) {
        Object value = get(key);
        if (value != null && type.isAssignableFrom(value.getClass())) {
            return (T) value;
        }
        return null;
    }

    /**
     * 删除缓存
     * 
     * @param key 键
     * @return 是否删除成功
     */
    public boolean delete(String key) {
        try {
            return Boolean.TRUE.equals(redisTemplate.delete(key));
        } catch (Exception e) {
            log.error("删除Redis缓存失败: {}", key, e);
            return false;
        }
    }

    /**
     * 批量删除缓存
     * 
     * @param keys 键集合
     * @return 删除的数量
     */
    public long delete(Collection<String> keys) {
        try {
            Long count = redisTemplate.delete(keys);
            return count != null ? count : 0;
        } catch (Exception e) {
            log.error("批量删除Redis缓存失败", e);
            return 0;
        }
    }

    /**
     * 根据模式删除缓存
     * 
     * @param pattern 模式
     * @return 删除的数量
     */
    public long deleteByPattern(String pattern) {
        try {
            Set<String> keys = redisTemplate.keys(pattern);
            if (keys != null && !keys.isEmpty()) {
                return delete(keys);
            }
            return 0;
        } catch (Exception e) {
            log.error("根据模式删除Redis缓存失败: {}", pattern, e);
            return 0;
        }
    }

    /**
     * 检查键是否存在
     * 
     * @param key 键
     * @return 是否存在
     */
    public boolean exists(String key) {
        try {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            log.error("检查Redis键是否存在失败: {}", key, e);
            return false;
        }
    }

    /**
     * 设置过期时间
     * 
     * @param key 键
     * @param timeout 过期时间
     * @param unit 时间单位
     * @return 是否设置成功
     */
    public boolean expire(String key, long timeout, TimeUnit unit) {
        try {
            return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
        } catch (Exception e) {
            log.error("设置Redis键过期时间失败: {}", key, e);
            return false;
        }
    }

    /**
     * 设置过期时间
     * 
     * @param key 键
     * @param duration 过期时间
     * @return 是否设置成功
     */
    public boolean expire(String key, Duration duration) {
        return expire(key, duration.toMillis(), TimeUnit.MILLISECONDS);
    }

    /**
     * 获取剩余过期时间
     * 
     * @param key 键
     * @return 剩余时间（秒）
     */
    public long getExpire(String key) {
        try {
            Long expire = redisTemplate.getExpire(key);
            return expire != null ? expire : -1;
        } catch (Exception e) {
            log.error("获取Redis键剩余过期时间失败: {}", key, e);
            return -1;
        }
    }

    /**
     * 原子递增
     * 
     * @param key 键
     * @param delta 增量
     * @return 递增后的值
     */
    public long increment(String key, long delta) {
        try {
            Long value = redisTemplate.opsForValue().increment(key, delta);
            return value != null ? value : 0;
        } catch (Exception e) {
            log.error("Redis原子递增失败: {}", key, e);
            return 0;
        }
    }

    /**
     * 原子递减
     * 
     * @param key 键
     * @param delta 减量
     * @return 递减后的值
     */
    public long decrement(String key, long delta) {
        return increment(key, -delta);
    }

    /**
     * 获取所有匹配的键
     * 
     * @param pattern 模式
     * @return 键集合
     */
    public Set<String> keys(String pattern) {
        try {
            Set<String> keys = redisTemplate.keys(pattern);
            return keys != null ? keys : Set.of();
        } catch (Exception e) {
            log.error("获取Redis键失败: {}", pattern, e);
            return Set.of();
        }
    }

    /**
     * 获取缓存大小
     * 
     * @param pattern 模式
     * @return 缓存大小
     */
    public long size(String pattern) {
        Set<String> keys = keys(pattern);
        return keys.size();
    }

    /**
     * 清空所有缓存
     */
    @SuppressWarnings("deprecation")
    public void flushAll() {
        try {
            redisTemplate.getConnectionFactory().getConnection().flushAll();
        } catch (Exception e) {
            log.error("清空Redis缓存失败", e);
        }
    }
}
